﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace iNet.Media.Xmp
{
	#region XmpProperty
	/// <summary>
	/// 表示一個 XMP Property。
	/// </summary>
	public class XmpProperty : ICloneable
	{
		#region 欄位
		XmpPropertyName _Name;
		XmpPropertyValue _Value;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 XmpProperty 執行個體。
		/// </summary>
		/// <param name="name">名稱。</param>
		/// <param name="value">值。</param>
		/// <exception cref="ArgumentNullException">name 為 Null (Visual Basic 為 Nothing)。</exception>
		public XmpProperty(XmpPropertyName name, XmpPropertyValue value)
		{
			if (name == null)
				throw new ArgumentNullException("name");
			_Name = name;
			_Value = value;
		}
		/// <summary>
		/// 初始化新的 XmpProperty 執行個體。
		/// </summary>
		/// <param name="localName">Property 的區域名稱。</param>
		/// <exception cref="ArgumentNullException">localName 為 Null (Visual Basic 為 Nothing)。</exception>
		public XmpProperty(string localName)
			: this(localName, null)
		{ }
		/// <summary>
		/// 初始化新的 XmpProperty 執行個體。
		/// </summary>
		/// <param name="localName">Property 的區域名稱。</param>
		/// <param name="value">Property 值。</param>
		/// <exception cref="ArgumentNullException">localName 為 Null (Visual Basic 為 Nothing)。</exception>
		public XmpProperty(string localName, XmpPropertyValue value)
			: this(null, localName, value)
		{ }
		/// <summary>
		/// 初始化新的 XmpProperty 執行個體。
		/// </summary>
		/// <param name="schema">Property 所屬的 XMP Schema。</param>
		/// <param name="localName">Property 的區域名稱。</param>
		/// <param name="value">Property 值。</param>
		/// <exception cref="ArgumentNullException">localName 為 Null (Visual Basic 為 Nothing)。</exception>
		public XmpProperty(XmpSchema schema, string localName, XmpPropertyValue value)
			: this(new XmpPropertyName(schema, localName), value)
		{ }
		#endregion
		#region Clone
		/// <summary>
		/// 建立副本。
		/// </summary>
		/// <returns>XmpProperty 副本。</returns>
		public XmpProperty Clone()
		{
			return new XmpProperty(_Name.Clone(), _Value.Clone<XmpPropertyValue>());
		}
		#endregion
		#region ICloneable.Clone
		object ICloneable.Clone()
		{
			return this.Clone();
		}
		#endregion
		#region Name
		/// <summary>
		/// 取得或設定名稱。
		/// </summary>
		public XmpPropertyName Name
		{
			get
			{
				return _Name;
			}
			set
			{
				if (value == null)
					throw new ArgumentNullException();
				_Name = value;
			}
		}
		#endregion
		#region Value
		/// <summary>
		/// 取得或設定 XMP Property 的值。
		/// </summary>
		public XmpPropertyValue Value
		{
			get
			{
				return _Value;
			}
			set
			{
				_Value = value;
			}
		}
		#endregion
	}
	#endregion
	#region XmpPropertyName
	/// <summary>
	/// 表示 XMP Property 的名稱。
	/// </summary>
	public class XmpPropertyName : ICloneable
	{
		#region 欄位
		string _LocalName;
		XmpSchema _Schema;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 XmpPropertyName 執行個體。
		/// </summary>
		/// <param name="schema">所屬的 XMP Schema。</param>
		/// <param name="localName">區域名稱。</param>
		/// <exception cref="ArgumentNullException">localName 為 Null (Visual Basic 為 Nothing)。</exception>
		public XmpPropertyName(XmpSchema schema, string localName)
		{
			if (localName == null)
				throw new ArgumentNullException("localName");
			_Schema = schema;
			_LocalName = localName;
		}
		#endregion
		#region Clone
		/// <summary>
		/// 製作 XmpPropertyName 的副本。
		/// </summary>
		/// <returns>新的 XmpPropertyName 物件。</returns>
		public XmpPropertyName Clone()
		{
			return new XmpPropertyName(_Schema, _LocalName);
		}
		#endregion
		#region Equals
		/// <summary>
		/// 和另一個物件比較是否相等。
		/// </summary>
		/// <param name="obj">另一個物件。</param>
		/// <returns>是否相等。</returns>
		public override bool Equals(object obj)
		{
			//轉成 XmpPropertyName
			XmpPropertyName other = (obj as XmpPropertyName);

			//比較內容
			if (other != null && string.Equals(_LocalName, other._LocalName))
				return ((_Schema != null && _Schema.Equals(other._Schema)) || (_Schema == null && other._Schema == null));
			return false;
		}
		#endregion
		#region GetHashCode
		/// <summary>
		/// 取得名稱的雜湊碼。
		/// </summary>
		/// <returns>雜湊碼。</returns>
		public override int GetHashCode()
		{
			if (_Schema != null)
			{
				if (_LocalName != null)
					return (_Schema.GetHashCode() * _LocalName.GetHashCode());
				return _Schema.GetHashCode();
			}
			else if (_LocalName != null)
				return _LocalName.GetHashCode();
			return 0;
		}
		#endregion
		#region ICloneable.Clone
		object ICloneable.Clone()
		{
			return this.Clone();
		}
		#endregion
		#region LocalName
		/// <summary>
		/// 取得區域名稱。
		/// </summary>
		public string LocalName
		{
			get
			{
				return _LocalName;
			}
		}
		#endregion
		#region Schema
		/// <summary>
		/// 取得所屬的 XMP Schema。
		/// </summary>
		public XmpSchema Schema
		{
			get
			{
				return _Schema;
			}
		}
		#endregion
		#region ToString
		/// <summary>
		/// 取得 XMP Property 名稱的字串表示。
		/// </summary>
		/// <returns>XMP Property 名稱的字串表示。</returns>
		public override string ToString()
		{
			if (_Schema != null)
				return _Schema.NamespacePrefix + ":" + _LocalName;
			return _LocalName;
		}
		#endregion
	}
	#endregion
	#region XmpPropertyQualifier
	/// <summary>
	/// 表示一個 XMP Property Qualifier。
	/// </summary>
	public class XmpPropertyQualifier : ICloneable
	{
		#region 建構子
		/// <summary>
		/// 初始化新的 XmpPropertyQualifier 執行個體。
		/// </summary>
		/// <param name="schema">所屬的 XMP Schema。</param>
		/// <param name="name">名稱。</param>
		/// <param name="value">值。</param>
		public XmpPropertyQualifier(XmpSchema schema, string name, string value)
		{
			this.Schema = schema;
			this.Name = name;
			this.Value = value;
		}
		#endregion
		#region Clone
		/// <summary>
		/// 建立副本。
		/// </summary>
		/// <returns>XmpPropertyQualifier 副本。</returns>
		public XmpPropertyQualifier Clone()
		{
			return new XmpPropertyQualifier(this.Schema, this.Name, this.Value);
		}
		#endregion
		#region ICloneable.Clone
		object ICloneable.Clone()
		{
			return this.Clone();
		}
		#endregion
		#region Name
		/// <summary>
		/// 取得或設定名稱。
		/// </summary>
		public string Name { get; set; }
		#endregion
		#region Schema
		/// <summary>
		/// 取得或設定所屬的 XMP Schema。
		/// </summary>
		public XmpSchema Schema { get; set; }
		#endregion
		#region Value
		/// <summary>
		/// 取得或設定值。
		/// </summary>
		public string Value { get; set; }
		#endregion
	}
	#endregion
	#region CommonXmpSchemas
	/// <summary>
	/// 提供常用的 XMP Schema 資訊。
	/// </summary>
	public static class CommonXmpSchemas
	{
		#region 唯讀欄位
		/// <summary>
		/// Adobe PDF Schema。
		/// </summary>
		public static readonly XmpSchema AdobePDF = new XmpSchema("pdf", "http://ns.adobe.com/pdf/1.3/");
		/// <summary>
		/// Camera Raw Schema。
		/// </summary>
		public static readonly XmpSchema CameraRaw = new XmpSchema("crs", "http://ns.adobe.com/camera-rawsettings/1.0/");
		/// <summary>
		/// Dublin Core Schema。
		/// </summary>
		public static readonly XmpSchema DublinCore = new XmpSchema("dc", "http://purl.org/dc/elements/1.1/");
		/// <summary>
		/// EXIF Schema for Additional EXIF Properties。
		/// </summary>
		public static readonly XmpSchema ExifAdditional = new XmpSchema("aux", "http://ns.adobe.com/exif/1.0/aux/");
		/// <summary>
		/// EXIF Schema for EXIF-specific Properties。
		/// </summary>
		public static readonly XmpSchema ExifSpecific = new XmpSchema("exif", "http://ns.adobe.com/exif/1.0/");
		/// <summary>
		/// IPTC Core Schema。
		/// </summary>
		public static readonly XmpSchema IptcCore = new XmpSchema("Iptc4xmpCore", "http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/");
		/// <summary>
		/// Microsoft Photo 1.0 Schema。
		/// </summary>
		public static readonly XmpSchema MicrosoftPhoto = new XmpSchema("MicrosoftPhoto", "http://ns.microsoft.com/photo/1.0/");
		/// <summary>
		/// Microsoft Photo 1.2 Schema。
		/// </summary>
		public static readonly XmpSchema MicrosoftPhoto_1_2 = new XmpSchema("MP", "http://ns.microsoft.com/photo/1.2/");
		/// <summary>
		/// Photoshop Schema。
		/// </summary>
		public static readonly XmpSchema Photoshop = new XmpSchema("photoshop", "http://ns.adobe.com/photoshop/1.0/");
		/// <summary>
		/// RDF Schema。
		/// </summary>
		public static readonly XmpSchema RDF = new XmpSchema("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
		/// <summary>
		/// EXIF Schema for TIFF Properties。
		/// </summary>
		public static readonly XmpSchema Tiff = new XmpSchema("tiff", "http://ns.adobe.com/tiff/1.0/");
		/// <summary>
		/// XMP Basic Schema。
		/// </summary>
		public static readonly XmpSchema XmpBasic = new XmpSchema("xmp", "http://ns.adobe.com/xap/1.0/");
		/// <summary>
		/// XMP Basic Job Ticket Schema。
		/// </summary>
		public static readonly XmpSchema XmpBasicJobTicket = new XmpSchema("xmpBJ", "http://ns.adobe.com/xap/1.0/bj/");
		/// <summary>
		/// XMP Dynamic Media Schema。
		/// </summary>
		public static readonly XmpSchema XmpDynamicMedia = new XmpSchema("xmpDM", "http://ns.adobe.com/xmp/1.0/DynamicMedia/");
		/// <summary>
		/// XMP Media Management Schema。
		/// </summary>
		public static readonly XmpSchema XmpMediaManagement = new XmpSchema("xmpMM", "http://ns.adobe.com/xap/1.0/mm/");
		/// <summary>
		/// XMP Paged-Text Schema。
		/// </summary>
		public static readonly XmpSchema XmpPagedText = new XmpSchema("xmpTPg", "http://ns.adobe.com/xap/1.0/t/pg/");
		/// <summary>
		/// XMP Rights Management Schema。
		/// </summary>
		public static readonly XmpSchema XmpRightsManagement = new XmpSchema("xmpRights", "http://ns.adobe.com/xap/1.0/rights/");
		#endregion
		#region 欄位
		static Dictionary<string, XmpSchema> _SchemasByURI = new Dictionary<string, XmpSchema>();
		#endregion
		#region 型別建構子
		static CommonXmpSchemas()
		{
			//初始化 Namespace URI 對照表
			_SchemasByURI[CommonXmpSchemas.AdobePDF.NamespaceURI] = CommonXmpSchemas.AdobePDF;
			_SchemasByURI[CommonXmpSchemas.CameraRaw.NamespaceURI] = CommonXmpSchemas.CameraRaw;
			_SchemasByURI[CommonXmpSchemas.DublinCore.NamespaceURI] = CommonXmpSchemas.DublinCore;
			_SchemasByURI[CommonXmpSchemas.ExifAdditional.NamespaceURI] = CommonXmpSchemas.ExifAdditional;
			_SchemasByURI[CommonXmpSchemas.Tiff.NamespaceURI] = CommonXmpSchemas.Tiff;
			_SchemasByURI[CommonXmpSchemas.ExifSpecific.NamespaceURI] = CommonXmpSchemas.ExifSpecific;
			_SchemasByURI[CommonXmpSchemas.IptcCore.NamespaceURI] = CommonXmpSchemas.IptcCore;
			_SchemasByURI[CommonXmpSchemas.MicrosoftPhoto.NamespaceURI] = CommonXmpSchemas.MicrosoftPhoto;
			_SchemasByURI[CommonXmpSchemas.MicrosoftPhoto_1_2.NamespaceURI] = CommonXmpSchemas.MicrosoftPhoto_1_2;
			_SchemasByURI[CommonXmpSchemas.Photoshop.NamespaceURI] = CommonXmpSchemas.Photoshop;
			_SchemasByURI[CommonXmpSchemas.XmpBasic.NamespaceURI] = CommonXmpSchemas.XmpBasic;
			_SchemasByURI[CommonXmpSchemas.XmpBasicJobTicket.NamespaceURI] = CommonXmpSchemas.XmpBasicJobTicket;
			_SchemasByURI[CommonXmpSchemas.XmpDynamicMedia.NamespaceURI] = CommonXmpSchemas.XmpDynamicMedia;
			_SchemasByURI[CommonXmpSchemas.XmpMediaManagement.NamespaceURI] = CommonXmpSchemas.XmpMediaManagement;
			_SchemasByURI[CommonXmpSchemas.XmpPagedText.NamespaceURI] = CommonXmpSchemas.XmpPagedText;
			_SchemasByURI[CommonXmpSchemas.XmpRightsManagement.NamespaceURI] = CommonXmpSchemas.XmpRightsManagement;
		}
		#endregion
		#region GetSchemaByNamespaceURI
		/// <summary>
		/// 使用指定的 Schema Namespace URI 搜尋對應的 XMP Schema 資訊。
		/// </summary>
		/// <param name="namespaceURI">指定的 Schema Namespace URI。</param>
		/// <returns>對應的 XMP Schema 資訊，Null (Visual Basic 為 Nothing) 表示沒有對應的 XMP Schema 資訊。</returns>
		/// <exception cref="ArgumentNullException">namespaceURI 為 Null (Visual Basic 為 Nothing)。</exception>
		public static XmpSchema GetSchemaByNamespaceURI(string namespaceURI)
		{
			//確認
			if (namespaceURI == null)
				throw new ArgumentNullException("namespaceURI");

			//搜尋並回傳
			XmpSchema schema;
			_SchemasByURI.TryGetValue(namespaceURI, out schema);
			return schema;
		}
		#endregion
	}
	#endregion
	#region XmpSchema
	/// <summary>
	/// 表示一個 XMP Schema。
	/// </summary>
	public class XmpSchema : ICloneable
	{
		#region 欄位
		bool _IsReadOnly;
		string _NamespacePrefix;
		string _NamespaceURI;
		#endregion
		#region 建構子
		/// <summary>
		/// 初始化新的 XmpSchema 執行個體。
		/// </summary>
		/// <param name="namespacePrefix">Schema Namespace 前置詞。</param>
		/// <param name="namespaceURI">Schema Namespace URI。</param>
		/// <exception cref="ArgumentNullException">namespacePrefix 或 namespaceURI 為 Null (Visual Basic 為 Nothing)。</exception>
		public XmpSchema(string namespacePrefix, string namespaceURI)
		{
			//確認參數
			if (namespacePrefix == null)
				throw new ArgumentNullException("namespacePrefix");
			if (namespaceURI == null)
				throw new ArgumentNullException("namespaceURI");

			//初始化
			_NamespacePrefix = namespacePrefix;
			_NamespaceURI = namespaceURI;
		}
		/// <summary>
		/// 初始化新的 XmpSchema 執行個體。
		/// </summary>
		/// <param name="schema">現有的 XMP Schema。</param>
		/// <exception cref="ArgumentNullException">schema 為 Null (Visual Basic 為 Nothing)。</exception>
		public XmpSchema(XmpSchema schema)
		{
			//確認
			if (schema == null)
				throw new ArgumentNullException("schema");

			//初始化
			_NamespacePrefix = schema._NamespacePrefix;
			_NamespaceURI = schema._NamespaceURI;
		}
		#endregion
		#region Clone
		/// <summary>
		/// 建立副本。
		/// </summary>
		/// <returns>XmpSchema 副本。</returns>
		public XmpSchema Clone()
		{
			return new XmpSchema(this);
		}
		#endregion
		#region Equals
		/// <summary>
		/// 和另一個物件比較是否相等。
		/// </summary>
		/// <param name="obj">另一個物件。</param>
		/// <returns>是否相等。</returns>
		public override bool Equals(object obj)
		{
			//轉成 XmpSchema
			XmpSchema other = (obj as XmpSchema);

			//比較內容
			if (other != null)
				return string.Equals(_NamespaceURI, other._NamespaceURI);
			return false;
		}
		#endregion
		#region GetHashCode
		/// <summary>
		/// 取得雜湊碼。
		/// </summary>
		/// <returns>雜湊碼。</returns>
		public override int GetHashCode()
		{
			if (_NamespaceURI != null)
				return _NamespaceURI.GetHashCode();
			return 0;
		}
		#endregion
		#region ICloneable.Clone
		object ICloneable.Clone()
		{
			return this.Clone();
		}
		#endregion
		#region NamespacePrefix
		/// <summary>
		/// 取得或設定 Schema Namespace 的前置詞。
		/// </summary>
		public string NamespacePrefix
		{
			get
			{
				return _NamespacePrefix;
			}
		}
		#endregion
		#region NamespaceURI
		/// <summary>
		/// 取得或設定 Schema Namespace 的 URI。
		/// </summary>
		public string NamespaceURI
		{
			get
			{
				return _NamespaceURI;
			}
		}
		#endregion
	}
	#endregion
}
